package com.jsbs.iam.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.jsbs.iam.common.core.utils.bean.BeanUtils;
import com.jsbs.iam.common.redis.service.RedisUtils;
import com.jsbs.iam.user.constant.Constants;
import com.jsbs.iam.user.constant.RedisConstants;
import com.jsbs.iam.user.entity.IamApplyMenu;
import com.jsbs.iam.user.entity.IamButton;
import com.jsbs.iam.user.mapper.IamAdminRoleMapper;
import com.jsbs.iam.user.mapper.IamApplyMenuMapper;
import com.jsbs.iam.user.mapper.IamButtonMapper;
import com.jsbs.iam.user.service.IamAdminRoleUserInfoService;
import com.jsbs.iam.user.service.IamMenuService;
import com.jsbs.iam.user.vo.IamMenuVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class IamMenuServiceImpl implements IamMenuService {

    @Autowired
    private IamApplyMenuMapper iamApplyMenuMapper;

    @Autowired
    private IamButtonMapper iamButtonMapper;

    @Autowired
    private IamAdminRoleUserInfoService iamAdminRoleUserInfoService;

    @Autowired
    private IamAdminRoleMapper iamAdminRoleMapper;

    @Value("${_env.name}")
    private String envName;

    @Override
    public List<IamMenuVo> queryMenu() {
        // 先从缓存取，取不到查库，并重新入缓存
        List<IamMenuVo> menuVoList = RedisUtils.getObjectList(envName + RedisConstants.IAM_SYSTEM_MENU, IamMenuVo.class);
        // 缓存存在直接返回
        if (CollectionUtils.isNotEmpty(menuVoList)) {
            return menuVoList;
        }
        // 获取IAM后台系统所有菜单
        List<IamApplyMenu> menuList = iamApplyMenuMapper.queryByApplyCode(Constants.IAM_APPLY_CODE);
        if (CollectionUtils.isEmpty(menuList)) {
            return null;
        }
        List<String> menuCodeList = menuList.stream().map(item -> item.getMenuCode()).collect(Collectors.toList());
        List<IamButton> buttonList = new ArrayList<>();
        // 根据菜单获取所有按钮列表
        if (CollectionUtils.isNotEmpty(menuCodeList)) {
            buttonList = iamButtonMapper.queryByMenuCode(menuCodeList);
        }
        // 获取所有一级菜单，根据菜单编码排序，并转换成vo
        menuVoList = menuList.stream().filter(item -> 1 == item.getMenuLevel()).map(this::beanCopys).sorted(Comparator.comparing(IamMenuVo::getMenuCode)).collect(Collectors.toList());
        // 递归封装子级菜单
        dealForIamMenu(menuList, menuVoList, buttonList);
        if (CollectionUtils.isEmpty(menuVoList)) {
            return null;
        }
        // 最新菜单列表入缓存，失效时间12小时
        RedisUtils.setObjectList(envName + RedisConstants.IAM_SYSTEM_MENU, menuVoList, 12, TimeUnit.HOURS);
        return menuVoList;
    }

    /**
     * 功能描述：递归封装子级菜单
     * @param menuList
     * @param iamMenuVos
     * @param buttonList
     */
    private void dealForIamMenu(List<IamApplyMenu> menuList, List<IamMenuVo> iamMenuVos, List<IamButton> buttonList){
        // 循环当前层级菜单
        iamMenuVos.forEach(item -> {
            List<IamMenuVo> menuVoList = new ArrayList<>();
            // 循环所有菜单，匹配当前菜单的所有子级菜单
            for (IamApplyMenu iamMenu : menuList) {
                if (item.getMenuCode().equalsIgnoreCase(iamMenu.getMenuSuperiorCode())) {
                    // 入集合
                    menuVoList.add(beanCopys(iamMenu));
                }
                // 递归封装当前菜单的子级菜单的所有子级
                dealForIamMenu(menuList, menuVoList, buttonList);
                // 每次递归结束都拍一次序
                menuVoList.sort(Comparator.comparing(IamMenuVo::getMenuCode));
            }
            // 封装当前菜单的所有子级菜单集合
            item.setChildren(menuVoList);
            // 封装当前菜单的所有按钮集合
            item.setButtonList(buttonList.stream().filter(info -> item.getMenuCode().equals(info.getMenuCode())).collect(Collectors.toList()));
        });
    }

    /**
     * 功能描述：实体类复制
     * @param iamMenu
     * @return
     */
    private IamMenuVo beanCopys(IamApplyMenu iamMenu) {
        IamMenuVo iamMenuVo = new IamMenuVo();
        BeanUtils.copyProperties(iamMenu, iamMenuVo);
        return iamMenuVo;
    }

    @Override
    public List<IamMenuVo> queryAdminPermissonList(String userCode, String adminRoleCode) {
        // 超级管理员获取全部权限
        if (Constants.ADMIN_USER_CODE.equalsIgnoreCase(adminRoleCode)) {
            return queryMenu();
        }

        // 非超级管理员角色 先从缓存取
        List<IamMenuVo> menuVoList = RedisUtils.getObjectList(envName + RedisConstants.IAM_SYSTEM_MENU + "_" + adminRoleCode, IamMenuVo.class);
        if (CollectionUtils.isNotEmpty(menuVoList)) {
            return menuVoList;
        }
        // 对应的管理员角色ID
        Long roleId = iamAdminRoleUserInfoService.queryByRoleCode(adminRoleCode);
        if (Objects.isNull(roleId) || 0 == roleId.longValue()) {
            return new ArrayList<>();
        }
        // 根据管理员角色ID获取菜单ID
        List<Long> menuIdList = iamAdminRoleMapper.queryByRoleId(roleId);
        if (CollectionUtils.isEmpty(menuIdList)) {
            return new ArrayList<>();
        }
        // 根据菜单ID获取菜单列表
        List<IamApplyMenu> iamMenus = iamApplyMenuMapper.queryByMenuIds(menuIdList);
        if (CollectionUtils.isEmpty(iamMenus)) {
            return new ArrayList<>();
        }
        // 获取按钮主键ID列表
        List<Long> buttonIdList = iamApplyMenuMapper.getButtonListByMenuIds(roleId, menuIdList);
        List<IamButton> buttonList = new ArrayList<>();
        // 根据主键获取按钮列表
        if (CollectionUtils.isNotEmpty(buttonIdList)) {
            buttonList = iamButtonMapper.queryButtonByIDs(buttonIdList);
        }
        // 获取所有一级菜单，根据菜单编码排序，并转换成vo
        menuVoList = iamMenus.stream().filter(item -> 1 == item.getMenuLevel()).map(this::beanCopys).sorted(Comparator.comparing(IamMenuVo::getMenuCode)).collect(Collectors.toList());
        // 递归封装子级菜单
        dealForIamMenu(iamMenus, menuVoList, buttonList);
        log.info("普通管理员权限列表info:{}", JSON.toJSONString(menuVoList));
        if (CollectionUtils.isEmpty(menuVoList)) {
            return new ArrayList<>();
        }
        // 当前用户的IAM后台最新菜单权限列表入缓存，失效时间12小时
        RedisUtils.setObjectList(envName + RedisConstants.IAM_SYSTEM_MENU + "_" + adminRoleCode, menuVoList, 12, TimeUnit.HOURS);
        return menuVoList;
    }
}
